﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using PicoContainer;
using PicoContainer.Defaults;

namespace XEvolve.Core.Pico
{
    internal class XComponentAdapter : ConstructorInjectionComponentAdapter
    {

        public XComponentAdapter(object componentKey, Type componentImplementation,
                                 IParameter[] parameters) : base(componentKey, componentImplementation, parameters)
        {
        }

        public override object GetComponentInstance(IPicoContainer container)
        {
            var greediestSatisfiableConstructor = GetGreediestSatisfiableConstructor(container);
            return greediestSatisfiableConstructor.Invoke(GetConstructorArguments(container, greediestSatisfiableConstructor));
        }

        protected override ConstructorInfo GetGreediestSatisfiableConstructor(IPicoContainer container)
        {
            var constructors =
                ComponentImplementation.GetConstructors().OrderByDescending(ctor => ctor.GetParameters().Length);

            var satisfiableConstructor = constructors.FirstOrDefault(constructor => AreAllParametersDefinedInContainer(constructor.GetParameters(), container));
            if (satisfiableConstructor == null)
            {
                throw new UnsatisfiableDependenciesException("Can't found proper constructor for component " + ComponentImplementation);
            }
            return satisfiableConstructor;
        }

        protected new static object[] GetConstructorArguments(IPicoContainer container, ConstructorInfo ctor)
        {
            return ctor.GetParameters().Select(parameter => container.GetComponentInstance(parameter.ParameterType)).ToArray();
        }

        private static bool AreAllParametersDefinedInContainer(IEnumerable<ParameterInfo> parameters, IPicoContainer container)
        {
            return parameters.All(parameter => container.GetComponentAdapter(parameter.ParameterType) != null);
        }
    }
}